home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Entertainment / MacMud / Mud 4.0 / call_out.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-16  |  8.3 KB  |  349 lines  |  [TEXT/MPS ]

  1. #include <setjmp.h>
  2. #include <memory.h>
  3. #include <string.h>
  4.  
  5. #include "config.h"
  6. #include "lint.h"
  7. #include "interpret.h"
  8. #include "object.h"
  9.  
  10. /*
  11.  * This file implements delayed calls of functions.
  12.  *
  13.  * Allocate the structures several in one chunk, to get rid of malloc
  14.  * overhead.
  15.  */
  16.  
  17. #define CHUNK_SIZE    20
  18.  
  19. extern char *xalloc(), *string_copy(), *findstring();
  20. extern jmp_buf error_recovery_context;
  21. extern int error_recovery_context_exists;
  22.  
  23. struct call {
  24.     int delta;
  25.     char *function;
  26.     struct object *ob;
  27.     struct svalue *v;
  28.     int num_args;
  29.     struct call *next;
  30. #ifndef NLHACK
  31.     struct object *command_giver;
  32. #endif
  33. };
  34.  
  35. static struct call *call_list, *call_list_free;
  36. static int num_call;
  37.  
  38. extern struct { unsigned counter, size; } sbrk_stat;
  39.  
  40. /*
  41.  * Free a call out structure.
  42.  */
  43. static void free_call(cop)
  44.     struct call *cop;
  45. {
  46.     int i;
  47.  
  48.     for (i = 0; i < cop->num_args; i++)
  49.     free_svalue(&cop->v[i]);
  50.     if (cop->num_args)
  51.     xfree((char *)cop->v);
  52.     cop->next = call_list_free;
  53.     free_string(cop->function);
  54.     cop->function = 0;
  55.     free_object(cop->ob, "free_call");
  56. #ifndef NLHACK
  57.     if (cop->command_giver)
  58.     free_object(cop->command_giver, "free_call");
  59. #endif
  60.     cop->ob = 0;
  61.     call_list_free = cop;
  62. }
  63.  
  64. /*
  65.  * Setup a new call out.
  66.  */
  67. void new_call_out(ob, fun, delay, arg, num_args)
  68.     struct object *ob;
  69.     char *fun;
  70.     int delay;
  71.     struct svalue *arg;
  72.     int num_args;
  73. {
  74.     struct call *cop, **copp;
  75.     int i;
  76.  
  77.     if (delay < 1)
  78.     delay = 1;
  79.     if (!call_list_free) {
  80.     call_list_free =
  81.         (struct call *)xalloc(CHUNK_SIZE * sizeof (struct call));
  82.     for (i=0; i<CHUNK_SIZE - 1; i++)
  83.         call_list_free[i].next  = &call_list_free[i+1];
  84.     call_list_free[CHUNK_SIZE-1].next = 0;
  85.     num_call += CHUNK_SIZE;
  86.     }
  87.     cop = call_list_free;
  88.     call_list_free = call_list_free->next;
  89.     cop->function = make_shared_string(fun);
  90. #ifndef NLHACK
  91.     cop->command_giver = command_giver; /* save current player context */
  92.     if (command_giver)
  93.     add_ref(command_giver, "new_call_out");        /* Bump its ref */
  94. #endif
  95.     cop->ob = ob;
  96.     add_ref(ob, "call_out");
  97.     cop->num_args = num_args;
  98.     if (num_args) {
  99.     cop->v = (struct svalue *) xalloc(num_args * sizeof (struct svalue));
  100.     for (i = 0; i < num_args; i++)
  101.         assign_svalue_no_free(&cop->v[i], &arg[i]);
  102.     }
  103.     for (copp = &call_list; *copp; copp = &(*copp)->next) {
  104.     if ((*copp)->delta >= delay) {
  105.         (*copp)->delta -= delay;
  106.         cop->delta = delay;
  107.         cop->next = *copp;
  108.         *copp = cop;
  109.         return;
  110.     }
  111.     delay -= (*copp)->delta;
  112.     }
  113.     *copp = cop;
  114.     cop->delta = delay;
  115.     cop->next = 0;
  116. }
  117.  
  118. /*
  119.  * See if there are any call outs to be called. Set the 'command_giver'
  120.  * if it is a living object. Check for shadowing objects, which may also
  121.  * be living objects.
  122.  */
  123. void call_out() {
  124.     struct call *cop;
  125.     jmp_buf save_error_recovery_context;
  126.     int save_rec_exists, i;
  127.     struct object *save_command_giver;
  128.     extern struct object *command_giver;
  129.     extern struct object *current_interactive;
  130.     extern int current_time;
  131.     static int last_time;
  132.  
  133.     if (call_list == 0) {
  134.     last_time = current_time;
  135.     return;
  136.     }
  137.     if (last_time == 0)
  138.     last_time = current_time;
  139.     save_command_giver = command_giver;
  140.     current_interactive = 0;
  141.     call_list->delta -= current_time - last_time;
  142.     last_time = current_time;
  143.     memcpy((char *) save_error_recovery_context,
  144.        (char *) error_recovery_context, sizeof error_recovery_context);
  145.     save_rec_exists = error_recovery_context_exists;
  146.     error_recovery_context_exists = 1;
  147.     while (call_list && call_list->delta <= 0) {
  148.     /*
  149.      * Move the first call_out out of the chain.
  150.      */
  151.     cop = call_list;
  152.     call_list = call_list->next;
  153.     /*
  154.      * A special case:
  155.      * If a lot of time has passed, so that current call out was missed,
  156.      * then it will have a negative delta. This negative delta implies
  157.      * that the next call out in the list has to be adjusted.
  158.      */
  159.     if (call_list && cop->delta < 0)
  160.         call_list->delta += cop->delta;
  161.     if (!(cop->ob->flags & O_DESTRUCTED)) {
  162.         if (setjmp(error_recovery_context)) {
  163.         extern void clear_state();
  164.         clear_state();
  165.         debug_message("Error in call out.\n");
  166.         } else {
  167.         struct object *ob;
  168.  
  169.         ob = cop->ob;
  170.         while(ob->shadowing)
  171.             ob = ob->shadowing;
  172. #ifndef NLHACK
  173.         command_giver = 0;
  174.         if (cop->command_giver &&
  175.             !(cop->command_giver->flags & O_DESTRUCTED))
  176.         {
  177.             command_giver = cop->command_giver;
  178.         } else if (ob->flags & O_ENABLE_COMMANDS) {
  179.             command_giver = ob;
  180.         }
  181. #else
  182.         if (ob->flags & O_ENABLE_COMMANDS)
  183.             command_giver = ob;
  184.         else
  185.             command_giver = 0;
  186. #endif
  187.          current_object = ob;
  188.         for (i = 0; i < cop->num_args; i++) {
  189.             if (cop->v[i].type == T_OBJECT &&
  190.                (cop->v[i].u.ob->flags & O_DESTRUCTED))
  191.             {
  192.             push_number(0);
  193.             }
  194.             else
  195.             {
  196.             push_svalue(&cop->v[i]);
  197.             }
  198.         }
  199.         (void)apply(cop->function, cop->ob, cop->num_args);
  200.         }
  201.     }
  202.     free_call(cop);
  203.     }
  204.     memcpy((char *) error_recovery_context,
  205.        (char *) save_error_recovery_context,
  206.        sizeof error_recovery_context);
  207.     error_recovery_context_exists = save_rec_exists;
  208.     command_giver = save_command_giver;
  209. }
  210.  
  211. /*
  212.  * Throw away a call out. First call to this function is discarded.
  213.  * The time left until execution is returned.
  214.  * -1 is returned if no call out pending.
  215.  */
  216. int remove_call_out(ob, fun)
  217.     struct object *ob;
  218.     char *fun;
  219. {
  220.     struct call **copp, *cop;
  221.     int delay = 0;
  222.     char *sharestr;
  223.  
  224.     if (!(sharestr = findstring(fun)))
  225.     return -1;
  226.     for (copp = &call_list; *copp; copp = &(*copp)->next) {
  227.     delay += (*copp)->delta;
  228.     if ((*copp)->ob == ob && ((*copp)->function == sharestr)) {
  229.         cop = *copp;
  230.         if (cop->next)
  231.         cop->next->delta += cop->delta;
  232.         *copp = cop->next;
  233.         free_call(cop);
  234.         return delay;
  235.     }
  236.     }
  237.     return -1;
  238. }
  239.  
  240. int find_call_out(ob, fun)
  241.     struct object *ob;
  242.     char *fun;
  243. {
  244.     struct call **copp;
  245.     int delay = 0;
  246.     char *sharestr;
  247.  
  248.     if (!(sharestr = findstring(fun)))
  249.     return -1;
  250.     for (copp = &call_list; *copp; copp = &(*copp)->next) {
  251.     delay += (*copp)->delta;
  252.     if ((*copp)->ob == ob && (*copp)->function == sharestr) {
  253.         return delay;
  254.     }
  255.     }
  256.     return -1;
  257. }
  258.  
  259. int print_call_out_usage(verbose)
  260.     int verbose;
  261. {
  262.     int i;
  263.     struct call *cop;
  264.  
  265.     for (i=0, cop = call_list; cop; cop = cop->next)
  266.     i++;
  267.     if (verbose) {
  268.     add_message("\nCall out information:\n");
  269.     add_message("---------------------\n");
  270.     add_message("Number of allocated call outs: %8d, %8d bytes\n",
  271.             num_call, num_call * sizeof (struct call));
  272.     add_message("Current length: %d\n", i);
  273.     } else {
  274.     add_message("call out:\t\t\t%8d %8d (current length %d)\n", num_call,
  275.             num_call * sizeof (struct call), i);
  276.     }
  277.     return num_call * sizeof (struct call);
  278. }
  279.  
  280. #ifdef DEBUG
  281. void count_ref_from_call_outs()
  282. {
  283.     struct call *cop;
  284.     int i;
  285.  
  286.     for (cop = call_list; cop; cop = cop->next) {
  287.     for (i = 0; i < cop->num_args; i++) {
  288.         switch(cop->v[i].type)
  289.         {
  290.         case T_POINTER:
  291.         cop->v[i].u.vec->extra_ref++;
  292.         break;
  293.         case T_OBJECT:
  294.         cop->v[i].u.ob->extra_ref++;
  295.         break;
  296.         }
  297.         cop->ob->extra_ref++;
  298.     }
  299.     }
  300. }
  301. #endif
  302.  
  303. /*
  304.  * Construct an array of all pending call_outs. Every item in the array
  305.  * consists of 4 items (but only if the object not is destructed):
  306.  * 0:    The object.
  307.  * 1:    The function (string).
  308.  * 2:    The delay.
  309.  * 3:    The argument.
  310.  */
  311. struct vector *get_all_call_outs() {
  312.     int i, next_time;
  313.     struct call *cop;
  314.     struct vector *v;
  315.  
  316.     for (i=0, cop = call_list; cop; i++, cop = cop->next)
  317.     ;
  318.     v = allocate_array(i);
  319.     next_time = 0;
  320.     /*
  321.      * Take for granted that all items in an array are initialized to
  322.      * number 0.
  323.      */
  324.     for (i=0, cop = call_list; cop; i++, cop = cop->next) {
  325.     struct vector *vv, *vvv;
  326.     int j;
  327.  
  328.     next_time += cop->delta;
  329.     if (cop->ob->flags & O_DESTRUCTED)
  330.         continue;
  331.     vv = allocate_array(4);
  332.     vv->item[0].type = T_OBJECT;
  333.     vv->item[0].u.ob = cop->ob;
  334.     add_ref(cop->ob, "get_all_call_outs");
  335.     vv->item[1].type = T_STRING;
  336.     vv->item[1].string_type = STRING_SHARED;
  337.     vv->item[1].u.string = make_shared_string(cop->function);
  338.     vv->item[2].u.number = next_time;
  339.     vv->item[3].type = T_POINTER;
  340.     vvv = vv->item[3].u.vec = allocate_array(cop->num_args);
  341.     for (j = 0; j < cop->num_args; j++)
  342.         assign_svalue_no_free(&vvv->item[j], &cop->v[j]);
  343.  
  344.     v->item[i].type = T_POINTER;
  345.     v->item[i].u.vec = vv;        /* Ref count is already 1 */
  346.     }
  347.     return v;
  348. }
  349.